﻿/* MVT Charts for Silverlight - Version 1
 * 2008 by Mario Meir-Huber
 * mailto: i-mameir@microsoft.com
 *         mario@meirhuber.de
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Globalization;
using System.Diagnostics;
using ChartLibrary.Base;

/*
 * ChartLibrary.Charts is the Namespace for all charts.
 */
namespace ChartLibrary.Charts
{
    /// <summary>
    /// Stacked Bar Chart 100%
    /// </summary>
    public partial class StackedBarChart100 : AxisCharts
    {
        public event ItemHandler ItemMouseEnter;  //occurs when the mouse enters the item
        public event ItemHandler ItemMouseLeave;  //occurs when the mouse leaves the item
        public event ItemHandler ItemClicked;     //occurs when a mouse click is performed on the item

        /// <summary>
        /// Displays a stacked bar chart that is always 100% high
        /// </summary>
        public StackedBarChart100()
        {
            LayoutRoot.SizeChanged += new SizeChangedEventHandler(LayoutRoot_SizeChanged);

            this.DrawAreaChanged += new StateChangedEvent(StackedBarChart100_DrawAreaChanged);
        }

        /// <summary>
        /// occurs when the area was changed
        /// </summary>
        void StackedBarChart100_DrawAreaChanged()
        {
            UpdateChart();
        }

        /// <summary>
        /// occurs when the size was changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void LayoutRoot_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (e.NewSize.Height > 0 && e.NewSize.Width > 0) UpdateChart();
        }

        /// <summary>
        /// updates the chart
        /// </summary>
        private void UpdateChart()
        {
            double singleHeight = 0.0;
            double singleWidth = 0.0;
            double spacing = 10.0;

            double currcalc = 0.0;
            double currstart = 0.0;

            int count = -1;
            int length = 0;

            Rectangle rtTemp = null;
            Storyboard stTemp = null;

            bool running = true;

            //find the highest value
            foreach (Data.DataSource ds1 in Data)
            {
                if (ds1.Length > length) length = ds1.Length;
            }

            running = true;

            //iterates over all data sources
            foreach (Data.DataSource ds in Data)
            {
                singleWidth = (Area.Width - spacing * length - Area.StartX) / length;

                count = -1;

                while (running)
                {
                    count++;

                    running = false;

                    currstart = 0.0;

                    for (int i = 0; i < Data.Count; i++)
                    {
                        if (Data[i].Length > count)
                        {
                            currcalc = 0.0;

                            for (int j = 0; j < Data.Count; j++)
                            {
                                if (count < Data[j].Length)
                                {
                                    currcalc += Data[j][count].Value;
                                    running = true;
                                }
                            }

                            singleHeight = Math.Round(Area.Height / currcalc, 2);

                            rtTemp = LayoutRoot.FindName("rt_" + count.ToString() + "_" + i.ToString()) as Rectangle;

                            if (null == rtTemp)
                            {
                                rtTemp = new Rectangle();
                                rtTemp.SetValue(Canvas.NameProperty, "rt_" + count.ToString() + "_" + i.ToString());

                                TransformGroup tg = new TransformGroup();
                                tg.Children.Add(new ScaleTransform());
                                tg.Children.Add(new TranslateTransform());
                                rtTemp.RenderTransform = tg;

                                LayoutRoot.Children.Add(rtTemp);

                                rtTemp.MouseEnter += new MouseEventHandler(OnItemEnter);
                                rtTemp.MouseLeave += new MouseEventHandler(OnItemLeave);
                                rtTemp.MouseLeftButtonUp += new MouseButtonEventHandler(OnItemClick);
                            }

                            rtTemp.Fill = Data[i].Fill;

                            switch (ItemType)
                            {
                                case ChartLibrary.Base.ItemType.BarRadiusXY:
                                    {
                                        rtTemp.RadiusX = 10.0;
                                        rtTemp.RadiusY = 10.0;
                                        break;
                                    }
                                case ChartLibrary.Base.ItemType.BarRounded:
                                    {
                                        LinearGradientBrush lgr = new LinearGradientBrush();
                                        lgr.StartPoint = new Point(0.0, 0.5);
                                        lgr.EndPoint = new Point(1.0, 0.5);

                                        lgr.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(40, 255, 255, 255), Offset = 0.0 });
                                        lgr.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(255, 255, 255, 255), Offset = 0.20 });
                                        lgr.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(255, 255, 255, 255), Offset = 0.8 });
                                        lgr.GradientStops.Add(new GradientStop() { Color = Color.FromArgb(40, 255, 255, 255), Offset = 1 });

                                        rtTemp.OpacityMask = lgr;
                                        break;
                                    }
                                default:
                                    {
                                        rtTemp.RadiusX = 0.0;
                                        rtTemp.RadiusY = 0.0;
                                        rtTemp.OpacityMask = null;
                                        break;
                                    }
                            }

                            rtTemp.SetValue(Canvas.LeftProperty, spacing * (count + 1) + singleWidth * count + Area.StartX);
                            rtTemp.Height = Data[i][count].Value * singleHeight;
                            rtTemp.Width = singleWidth;

                            rtTemp.SetValue(Canvas.TopProperty, Area.Height - rtTemp.ActualHeight - currstart + Area.StartY);
                            currstart += rtTemp.ActualHeight;

                            running = true;

                            if (Animation == ChartLibrary.Base.Animation.FxOpacity || Animation == ChartLibrary.Base.Animation.FxOpacityAsynchrounous)
                            {
                                rtTemp.Opacity = 0.0;
                            }

                            stTemp = LayoutRoot.FindName("_story" + count.ToString() + "_" + i.ToString()) as Storyboard;

                            if (null == stTemp)
                            {
                                stTemp = AddAnimation((string)rtTemp.GetValue(Canvas.NameProperty), i, rtTemp.Height);

                                try
                                {
                                    stTemp.SetValue(Canvas.NameProperty, "_story" + count.ToString() + "_" + i.ToString());
                                    //LayoutRoot.Resources.Add(stTemp);

                                    stTemp.Completed += new EventHandler(stTemp_Completed);
                                    stTemp.Begin();
                                }
                                catch (Exception ex)
                                {
                                    Debug.WriteLine(ex.Message);
                                }
                            }
                            else
                            {
                                stTemp.Begin();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Occurs when the mouse enters an item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnItemLeave(object sender, MouseEventArgs e)
        {
            if (null != ItemMouseLeave) ItemMouseLeave(sender, new ItemEventArgs());
        }

        /// <summary>
        /// Occurs when an item was clicked
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnItemClick(object sender, MouseButtonEventArgs e)
        {
            if (null != ItemClicked)
            {
                ItemClicked(sender, new ItemEventArgs());
            }
        }

        /// <summary>
        /// Occurs when the mouse enters an item
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void OnItemEnter(object sender, MouseEventArgs e)
        {
            if (null != ItemMouseEnter) ItemMouseEnter(sender, new ItemEventArgs());
        }

        /// <summary>
        /// occurs when the storyboard finished
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void stTemp_Completed(object sender, EventArgs e)
        {
            Storyboard st = (Storyboard)sender;
            //LayoutRoot.Resources.Remove(st);
        }

        /// <summary>
        /// adds an animation to the storyboard
        /// </summary>
        /// <param name="target">target to animate</param>
        /// <param name="AsynchId">id, if it is an asynch animation</param>
        /// <param name="height">endposition</param>
        /// <returns></returns>
        private Storyboard AddAnimation(string target, int AsynchId, double height)
        {
            string anim = "";
            Storyboard retval = null;

            height = Math.Round(height, 2);

            switch (Animation)
            {
                default:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\"/>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxDropDown:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<PointAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransformOrigin)\"" +
                        " BeginTime=\"00:00:00\"><SplinePointKeyFrame KeyTime=\"00:00:00\" Value=\"0.5,0.0\"/></PointAnimationUsingKeyFrames>" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)\" " +
                        "BeginTime=\"00:00:00\">" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:00\" Value=\"0.0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.4).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.1\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.5).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.0\"/>" +
                        "</DoubleAnimationUsingKeyFrames>" +

                        "</Storyboard>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxDropDownAsynchronous:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<PointAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransformOrigin)\"" +
                        " BeginTime=\"00:00:00\"><SplinePointKeyFrame KeyTime=\"00:00:00\" Value=\"0.5,0.0\"/></PointAnimationUsingKeyFrames>" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)\" " +
                        "BeginTime=\"00:00:00\">" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:00\" Value=\"0.0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.1 * AsynchId).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.1\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.1 * AsynchId + 0.3).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.0\"/>" +
                        "</DoubleAnimationUsingKeyFrames>" +

                        "</Storyboard>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxRiseUp:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<PointAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransformOrigin)\"" +
                        " BeginTime=\"00:00:00\"><SplinePointKeyFrame KeyTime=\"00:00:00\" Value=\"0.5,1.0\"/></PointAnimationUsingKeyFrames>" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)\" " +
                        "BeginTime=\"00:00:00\">" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:00\" Value=\"0.0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.4).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.1\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.5).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.0\"/>" +
                        "</DoubleAnimationUsingKeyFrames>" +

                        "</Storyboard>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxRiseUpAsynchronous:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<PointAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransformOrigin)\"" +
                        " BeginTime=\"00:00:00\"><SplinePointKeyFrame KeyTime=\"00:00:00\" Value=\"0.5,1.0\"/></PointAnimationUsingKeyFrames>" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)\" " +
                        "BeginTime=\"00:00:00\">" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:00\" Value=\"0.0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.1 * AsynchId).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.1\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:" + (0.1 * AsynchId + 0.3).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"1.0\"/>" +
                        "</DoubleAnimationUsingKeyFrames>" +
                        "</Storyboard>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxOpacity:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.Opacity)\" " +
                        "BeginTime=\"00:00:00\"><SplineDoubleKeyFrame KeyTime=\"00:00:00\" Value=\"0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:00.5000000\" Value=\"1\"/></DoubleAnimationUsingKeyFrames></Storyboard>";
                        break;
                    }
                case ChartLibrary.Base.Animation.FxOpacityAsynchrounous:
                    {
                        anim = "<Storyboard xmlns=\"http://schemas.microsoft.com/client/2007\">" +
                        "<DoubleAnimationUsingKeyFrames Storyboard.TargetName=\"" + target + "\" Storyboard.TargetProperty=\"(UIElement.Opacity)\" " +
                        "BeginTime=\"00:00:00\"><SplineDoubleKeyFrame KeyTime=\"00:00:0" + (0.1 * AsynchId).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + "\" Value=\"0\"/>" +
                        "<SplineDoubleKeyFrame KeyTime=\"00:00:0" + (0.1 * AsynchId + 0.3).ToString(new NumberFormatInfo() { CurrencyDecimalSeparator = "." }) + " \" Value=\"1\"/></DoubleAnimationUsingKeyFrames></Storyboard>";
                        break;
                    }
            }

            retval = (Storyboard)System.Windows.Markup.XamlReader.Load(anim);

            return retval;
        }
    }
}
